M2.855 · Modelos avanzados de minería de datos · PEC4

2020-2 · Máster universitario en Ciencia de datos (Data science)

Estudios de Informática, Multimedia y Telecomunicación

 

PEC 4: Regresión y Combinación de clasificadores

Está práctica está dividida en dos partes:

Nombre y apellidos:

Francisco Javier Melchor González

Para esta PEC se deben usar únicamente las librerías que se importan a continuación. Si se desea usar otra librería hay que consultarlo con el tutor/tutora del aula.

1. Regresión (5 puntos)

En la primera parte de este ejercicio analizaremos los resultados de distintos modelos de regresión aplicados a tres conjuntos de datos sintéticos con los que veremos sus fortalezas y debilidades.

En la segunda parte aplicarermos el modelo que creamos más oportuno a un problema de la vida real.

1.1. Conjuntos de datos sintéticos

Generaremos tres conjuntos de datos con un único atributo descriptivo que utilizaremos para predecir el valor de la variable dependiente, pudiendo así visualizar en dos dimensiones el comportamiento de cada modelo.

Por otro lado, en los problemas de regresión podemos encontrar dos tipos de problemática diferente: interpolación (la predicción se realizará en base a atributos descriptivos dentro de un intervalo conocido) y extrapolación (alguno de sus atributos descriptivos toma valores fuera del rango de valores visto por el algoritmo durante la etapa de aprendizaje).

Como sólo dispondremos de un atributo descriptivo, pondremos un umbral en dicho atributo para diferenciar lo que sería interpolación (lo marcaremos en azul) de lo que sería extrapolación (en rojo). La gran diferencia entre estos dos subconjuntos de datos es que mientras parte de los datos que interpolaremos los utilizaremos para entrenar, ningún dato de los que extrapolaremos los utilizaremos en la etapa de aprendizaje.

En siguiente código genera y muestra los tres conjuntos de datos:

Con el objetivo de mostrar las capacidades de cada una de las técnicas de regresión sobre los tres conjuntos de datos generados, se facilita la siguient función que, dado un modelo, lo entrena para luego mostrar los resultados obtenidos, tanto en los casos de interpolación como de extrapolación.

Implementación:

Con ayuda de la función *plot_regressor_performance* que acabamos de definir, analiza el comportamiento de cada una de las siguientes técnicas: - regresión lineal - knn - svm - árbol de decisión Sugerencia: puedes encontrar la documentación de los modelos de regresión que has de utilizar en los siguientes enlaces: - LinearRegression: https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html - KNeighborsRegressor: https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsRegressor.html - SVR: https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVR.html - DecisionTreeRegressor: https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeRegressor.html

Regresión Lineal

KNN

SVM

Árbol de decisión

Análisis: ¿cómo se comporta cada modelo de regresión? ¿Qué modelos extrapolan?

Por lo general los modelos no se comportan adecuadamente para la problemática de extrapolación, excepto la regresión lineal, que logra adaptarse correctamente al Dataset linear incluso para el problema de extrapolación, pero esto es debido funcionamiento del modelo de regresión, pues este genera básicamente una ecuación lineal que se adapta lo máximo posible a los datos de entrenamiento dados y dicha ecuación resultante es utilizada posteriormente para realizar las diferentes predicciones, por lo que si el problema de extrapolación son datos que presentan una tendencia similar a la que presentan los datos con los que el modelo ha sido entrenado, el modelo logrará extrapolar correctamente, tal y como ocurre en este caso con el Dataset linear.

Señalar que esto no quiere decir que los modelos utilizados no logren extrapolar correctamente, sino que hemos utilizado los parámetros por defecto, si adaptasemos los modelos a los datos utilizados seguro que los resultados obtenidos para la problemática de extrapolación sería mucho mejor.

1.2 Conjunto de datos real

Buscando chollos en Taiwán

En este caso práctico utilizaremos un conjunto de datos público de precios de vivienda en Taiwán con el objetivo de encontrar las mejores ofertas del mercado. La descripción completa del conjunto de datos la podemos encontrar en el siguiente enlace: https://archive.ics.uci.edu/ml/datasets/Real+estate+valuation+data+set

Procedamos a cargar los datos en un DataFrame de pandas para su posterior uso:

La primera columna ("No") es un identificador numérico de la muestra. Las columnas "Xn ..." son los distintos atributos descriptivos. Finalmente, la columna "Y ..." es el valor objetivo o precio de la vivienda.

Extraemos del DataFrame la variable objetivo y los atributos descriptivos que vayamos a utilizar posteriormente en el modelo predictivo:

Implementación:

Es el momento de analizar qué pinta tienen los datos, para ello genera los histogramas de cada atributo descriptivo, muestra gráficas que relacionen cada uno de ellos con la variable objetivo. Sugerencia: también puede resultar útil observar la distribución geoespacial de los precios.
Análisis: ¿puedes deducir algo de las gráficas obtenidas?

Por un lado, podemos deducir a través de los histogramas que hay variación en las diferentes variables numéricas independientes, por lo que merece la pena, a priori, ver como se correlacionan todas ellas con la variable objetivo.

Por otro lado, a través de las gráficas de dispersión, podemos ver que las variables que más correlación presentan con la variable objetivo son:

Por otro lado, las variables "house age" y "number of convenience stores", no parecen presentar una variación clara en el precio de la vivienda (variable objetivo) dependiendo de los diferentes valores que toman las mismas, sobre todo en el caso de la variable "number of convenience stores", por lo que a priori, no parece que estas variables estén correlacionadas con la variable objetivo.

Implementación:

Con el conocimiento adquirido en el apartado 1.1 y teniendo en cuenta las distribuciones de los datos que acabamos de observar, elige la técnica de regresión que creas que mejor se ajusta al problema que queremos resolver. Divide el conjunto de datos original en train y test y aplica la técnica elegida.
Análisis: ¿por qué has elegido esa técnica? ¿Qué tal se comporta?

La razón por la que he elegido la técnica DecisionTreeRegressor, es porque es la técnica que ha resultado dar mejores resultados en el apartado 1.1 para los diferentes conjuntos de datos con los que se ha probado,tanto lineal como no lineal.

En este caso concreto, nos conviene que se adapte correctamente a tipos de datos no lineales, ya que como podemos ver en las gráficas de puntos generadas, las relaciones de la variable objetivo con las diferentes variables, no son lineales, sino que el valor de la variable objetivo va variando de menos a más en algunos intervalos, sobre todo en el caso de las variables "latitude" y "longitude". La relación con "distance to nearest MRT station" sin embargo, presenta menos variaciones y se trata de una correlación inversa (diminuye el precio a medida que aumenta la distancia), aunque más que linealmente, esta disminuye de manera exponencial.

Implementación:

Es el momento de aplicar el modelo que has entrenado con el subconjunto de train para buscar chollos en el subconjunto de test. Sugerencia: calcula la diferencia entre el valor predicho y el valor real del precio de cada vivienda del subconjunto de test para encontrar las viviendas más interesantes del mercado.

2. Combinación de clasificadores (5 puntos)

En este ejercicio utilizaremos un subconjunto de 5.000 imágenes provenientes del corpus EMNIST, constituido por carácteres y dígitos escritos a mano . Dicho subconjunto está formado por 1.000 imágenes para cada una de las 5 clases diferentes ("A", "B", "C", "D" y "E").

La primera parte de este ejercicio abordará la combinación de clasificadores en paralelo mediante las tecnicas de Bagging y Boosting.

Mientras que la segunda parte pretende mejorar los resultados aplicando tecnicas de combinación secuencial de clasificadores: Stacking y Cascading.

Para empezar, vamos a visualizar el dataset. Las imágenes tienen una resolución de 28x28 píxeles en escala de grises, por lo que se pueden representar utilizando un vector de 784 posiciones. El siguiente código cargará las 5.000 imágenes en la variable images y las correspondientes etiquetas (en forma numérica) en la variable labels. Podemos comprobar que la carga ha sido correcta obteniendo las dimensiones de estas dos variables.

Con el siguiente código podemos ver un ejemplo de imagen de cada una de las clases. Para ello reajustamos el vector de 784 dimensiones que representa cada imagen en una matriz de tamaño 28x28 y la transponemos para mostrarla:

Para poder probar varios modelos, primero vamos a dividir el dataset en train y test.

La división con la función train_test_split es aleatoria , pero para que todos obtengáis los mismos resultados y poder comentar dudas por el foro, fijaremos la seed para obtener los mismos datasets de train y test. El split tendrá en cuenta que los dos conjuntos tengan el mismo número de ejemplos para cada una de las clases gracias al parámetro stratify=labels.

Como en la segunda parte de este ejercicio trataremos stacking y cascading, y ambos se aplican sobre el conjunto de test, haremos un split del 50% para tener un poco más de base al aplicar estas dos técnicas.

2.1. Combinación paralela de clasificadores

2.1.1. Árbol de decisión

Para poder comparar el aumento de performance obtenido a medida que aplicamos técnicas nuevas, utilizaremos como baseline un simple árbol de decisión.

Implementación:

Evalúa la precisión de un árbol de decisión con profundidad máxima de 5 niveles (aplicaremos la misma restricción en las siguientes secciones) aplicando validación cruzada sobre el conjunto de datos de train. A continuación, entrena el mismo modelo sobre el conjunto de train, calcula y guarda las predicciones sobre el conjunto de test y calcula la precisión en el conjunto de test. Sugerencia: usar el módulo *cross_val_score* de *sklearn*. Para aprender más sobre *cross validation* y sobre cómo usar estos módulos, os recomendamos los siguientes enlaces: - http://scikit-learn.org/stable/modules/cross_validation.html - http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html

2.1.2. Bagging

2.1.2.a. Random Forest

La idea básica del bagging es utilizar el conjunto de entrenamiento original para generar centenares o miles de conjuntos similares usando muestreo con reemplazo. En este concepto está basado el algoritmo Random Forest, la combinación de varios árboles de decisión, cada uno entrenado con una realización diferente de los datos. La decisión final del clasificador combinado (el Random Forest) se toma por mayoría, dando el mismo peso a todas las decisiones parciales tomadas por los clasificadores base (los árboles).

Implementación:

Evalúa la precisión de un random forest combinando 20 árboles de decisión con profundidad máxima de 5 niveles aplicando validación cruzada sobre el conjunto de datos de train. A continuación, entrena el mismo modelo sobre el conjunto de train, calcula y guarda las predicciones sobre el conjunto de test y calcula la precisión en el conjunto de test. Sugerencia: usar el módulo *RandomForestClassifier* de *sklearn*. Para aprender a usar este módulo os recomendamos el siguiente enlace: - http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html
Análisis: ¿han mejorado los resultados respecto a un simple árbol de decisión? ¿Era de esperar?

Sí, los resultados de predicción obtenidos utilizando la técnica del bagging aplicada en el algoritmo Random Forest, basándonos en la precisión (accuracy) como medida de calidad, son mejores que los resultados obtenidos utilizando un árbol de decisión regresor simple.

Esta situación era de esperar, debido a que la técnica del bagging entrena a un conjunto de árboles con diferentes submuestras de datos de la muestra total de datos con la que se entrena al árbol de decisión simple, esto permite que en dichas submuestras sea más sencillo encontrar algunos patrones menos casuales que están presentes en los datos pero que en la muestra total resulta más difícil para un modelo detectarlos (al tener una causalidad pequeña frente al total de la muestra), y sin embargo en estas submuestras al tener un número menor de casos totales, resulta más sencilla la detección de dichos patrones para los diferentes árboles de decisión que componen el bosque aleatorio utilizado.

2.1.2.b. Out-of-bag

Una ventaja del bagging usado en el Random Forest es que cada uno de los árboles de decisión ha sido entrenado con una combinación diferente de los datos (muestreo con reemplazo), es decir, cada uno de los árboles no ha visto una determinada parte de los datos originales. Esto define una especie de conjunto de test para cada uno de los árboles, llamado out-of-bag, que puede ser usado para estimar el error del modelo sin necesidad de usar el conjunto de test real que creamos previamente, ni de usar estrategias de cross-validation.

Implementación:

Entrena sobre el conjunto de train un modelo de random forest combinando 20 árboles de decisión con profundidad máxima de 5 niveles y muestra la precisión de este modelo en el *out-of-bag*. Sugerencia: usar el módulo *RandomForestClassifier* de *sklearn*. Para aprender más sobre *out-of-bag* y sobre como usar este módulo (incluyendo el atributo *oob_score_*), os recomendamos los siguientes enlaces: - http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html - http://scikit-learn.org/stable/auto_examples/ensemble/plot_ensemble_oob.html
Análisis: ¿la precisión obtenida en el out-of-bag y con los métodos de validación anteriores son comparables? ¿Era de esperar?

La precisión obtenida en el out-of-bag ha resultado algo menor que la obtenida con los métodos de validación anteriores, aunque dicha diferencia no es grande.

Obtener una precisión menor al validar con el conjunto de test out-of-bag era de esperar, ya que es cuando los diferentes árboles de decisión que utiliza el bosque aleatorio, tienen que resolver la problemática de extrapolación, es decir, realizar predicciones de conjuntos de datos con los que no han sido entrenados, y esto resulta más difícil para los modelos, y por lo tanto la precisión obtenida es menor.

2.1.2.c. Número de clasificadores agregados

En los ejercicios anteriores hemos combinado 20 clasificadores simples en nuestro clasificador combinado. ¿Será que la precisión del clasificador combinado aumenta indefinidamente su desempeño si añadimos más clasificadores?

Para responder a esta pregunta vamos a representar una curva de validación. La curva de validación es una representación gráfica del desempeño de un modelo variando uno de sus parámetros. Esto nos permite entender cuál es el impacto de un determinado parámetro en el desempeño de un modelo.

Implementación:

Entrena varios modelos de Random Forest con un número de árboles cada vez mayor. Para cada modelo, calcula su precisón en el conjunto de test o usando *cross-validation* en el conjunto de entrenamiento. Opcional: representa gráficamente la evolución de la precisión con el número de árboles para ayudarte en el análisis de los resultados.

Sugerencia: usar el módulo *validation_curve* de sklearn. Para aprender a usar este módulo os recomendamos los siguientes enlaces:
- http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.validation_curve.html
- http://scikit-learn.org/stable/modules/learning_curve.html#validation-curve
Análisis: ¿incrementa indefinidamente la precisión con el número de árboles combinados o se satura en una precisión límite? ¿Por qué?

Tal y como se puede ver en la gráfica generada, el valor de la precisión va aumentando a medida que aumenta el número de estimadores (árboles combinados utilizados), pero hasta un límite que parece ser 100 según la gráfica.

Podemos ver que el valor de la precisión obtenida, a medida que aumenta el número de estimadores, al poner a prueba el modelo con los datos con los que ha sido entrenados (línea roja de la gráfica anterior) se mantiene en 1, lo que indica que el modelo de regresión obtenido logra resolver a la perfección el problema de interpolación para cualquier número de estimadores.

Pero sin embargo, si observamos el valor de la precisión obtenida al poner a prueba el modelo realizando una validación cruzada, vemos que dicho valor aumenta hasta alcanzar 100 en el número de estimadores, después comienza a bajar en los casos de 150 y 200. Esto es debido a que a medida que aumenta el número de estimadores el modelo tiende a sobreentrenarse, lo que quiere decir que el modelo aprende por completo lo que ocurre en el conjunto de datos con el que se entrena, pero sin embargo al recibir datos nuevos, es decir, al tener que resolver la problemática de extrapolación, no logra realizar las predicciones correctamente, ya que tiende a asociarlo de manera excesiva con la información con la que dicho modelo ha sido entrenado.

2.1.3. Boosting

En el sistema de Boosting se combinan varios clasificadores débiles sequencialmente, y en cada uno de ellos se da más peso a los datos que han sido erróneamente clasificados en las combinaciones anteriores, para que se concentre así en los casos más difíciles de resolver.

Implementación:

Evalúa la precisión de un gradient boosting con profundidad máxima de 5 niveles y 20 etapas de boosting aplicando validación cruzada sobre el conjunto de datos de train. A continuación, entrena el mismo modelo sobre el conjunto de train, calcula y guarda las predicciones sobre el conjunto de test y calcula la precisión en el conjunto de test. Sugerencia: usar el módulo *GradientBoostingClassifier* de sklearn. Para aprender a usar este módulo os recomendamos el siguiente enlace: - http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.GradientBoostingClassifier.html
Análisis: ¿han mejorado los resultados respecto a un simple árbol de decisión? ¿Era de esperar?

Basándonos en la precisión (accuracy) como medida de calidad, los resultados de utilizar la técnica de boosting aplicada al algoritmo de Random Forest con respecto a la utilización de un simple árbol de decisión, han mejorado notoriamente, pues hemos pasado de obtener una precisión de 0.79 a una precisión de 0.92.

Esto era de esperar, ya que la técnica de boosting, tal y como se indica anterioremente, da un mayor peso a aquellos datos que han sido clasificados erróneamente anteriormente, lo que permite no volver a cometer dichos errores en los futuros clasificadores y que por tanto la capacidad de predicción del modelo mejore.

En algunos casos este aumento no es muy notorio ya que el algoritmo del árbol de decisión es lo suficiente potente y no es posible mejorarlo, pero en este caso si ha sido posible mejorar el mismo.

2.2. Combinación secuencial de clasificadores base diferentes

Para poder hacer combinación secuencial de modelos, necessitamos tener varios modelos diferentes entrenados.

En nuestro caso, ya tenemos un árbol de decisión, el random forest y el gradient boosting. Vamos a entrenar un par de modelos más.

2.2.1 Clasificadores adicionales

Implementación:

Entrena un k-neighbors con 2 vecinos sobre el conjunto de datos de train, calcula y guarda las predicciones sobre el conjunto de test y calcula la precisión en el conjunto de test. Entrena un SVM (Suport vector machines) con gamma = 0.07 sobre el conjunto de datos de train, calcula y guarda las predicciones sobre el conjunto de test y calcula la precisión en el conjunto de test.
Análisis: comenta los resultados.

2.2.2 Stacking

Un clasificador de stacking usa como atributos las predicciones hechas por otros clasificadores en lugar de los datos originales de entrada.

Implementación:

Construye un clasificador de stacking usando un Gradient Boosting (con profundidad máxima de 5 niveles y 20 etapas de boosting) que use como atributos las predicciones hechas en el conjunto de test por los algoritmos: - árbol de decisión - random forest - gradient boosting - knn - svm Calcula la precisión del modelo resultante con *cross-validation* en el conjunto de test (en este caso no tenemos conjunto de train, con lo cual se hace directamente cross-validation sobre test). Sugerencia: usar la función column_stack de numpy para juntar todas las predicciones. Dado que las variables que usaremos ahora como predictors son categóricas, es preferible transformarlas en *dummies* (*one-hot-encoding*). Para apender a usar estas funciones os recomendamos los siguientes enlaces: - https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.column_stack.html - https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html
Análisis: ¿has conseguido mejorar la precisión gracias al stacking? Comenta los resultados.

Si comparamos los resultados obtenidos de aplicar el Stacking con el clasificador GradientBoosting entrenado anteriormente, que es el clasificador que ha mejores resultados de predicción ha dado, podemos decir que hemos mejorado la precisión, pero mínimamente, pues hemos pasado de tener 0.922 de precisión y una desviación estándar de 0.014 en el GradientBoosting anterior, y en este, aplicando la técnica de Stacking hemos conseguido obtener 0.927 y 0.010 de desviación estándar, lo que refleja que hemos mejorado la precisión y la desviación estándar, pero muy poco, debido a que el método GradientBoosting anterior ya daba muy buenos resultados y mejorarlo de manera realmente notoria era muy complicado.

Sin embargo si lo comparamos con otros clasificadores como puede ser el árbol de decisión o el modelo de SVM sobre todo, vemos que al combinar estos modelos con los demás se obtienen muy buenos resultados.

2.2.3. Cascading

El caso de cascading es parecido al de stacking pero utilizando no solamente las predicciones parciales de los clasificadores base, sino también los datos originales.

Implementación:

Construye un clasificador de cascading usando un Gradient Boosting (con profundidad máxima de 5 niveles y 20 etapas de boosting) que use como atributos las predicciones obtenidas con los modelos anteriores en el conjunto de test (igual que con el stacking), y también las variables originales. Calcula la precisión del modelo resultante con *cross-validation* en el conjunto de test. Sugerencia: Usa el mismo conjunto de datos que en el ejercicio anterior pero añade `X_test`.
Análisis: ¿has conseguido mejorar la precisión gracias al cascading? Comenta los resultados.

Aplicando la técnica de Cascading, se ha conseguido mejorar la precisión de los modelos de los que este se compone, incluso del GradientBoosting de una manera más notoria que aplicando la técnica de Stacking, pues hemos pasado de tener una precisión de 0.922 y una desviación estándar de 0.014 a tener una precisión de 0.942 y una desviación estándar de 0.011, es decir, hemos pasado de predecir correctamente un 92% de los datos de media al aplicar cross_validation, a predecir un 94%.

Si además de con el modelo de GradientBoosting, comparamos el modelo obtenido con otros modelos más simples de los que se compone, como puede ser SVM o el árbol de decisión, la mejora es muy notoria.